home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / comm / comm2 / hdrbb111.lha / HBBS / Source / Library / HBBSCommon.c < prev    next >
C/C++ Source or Header  |  1996-11-07  |  64KB  |  2,489 lines

  1. /*
  2.  
  3.   todo
  4.   ====
  5.  
  6.   remove LIBCountListItems(), replace with HBBS_NodesInList()  :-)
  7.  
  8. */
  9.  
  10. #define HBBSCOMMON
  11. #define MAIN
  12.  
  13. #include <ctype.h>
  14. #include <time.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include <exec/exec.h>
  20. #include <exec/types.h>
  21.  
  22. #include <dos/dos.h>
  23. #include <dos/dostags.h>
  24. #include <dos/filehandler.h>
  25. #include <dos/dosextens.h>
  26.  
  27. #include <libraries/reqtools.h>
  28.  
  29.  
  30. #include <clib/exec_protos.h>
  31. #include <clib/dos_protos.h>
  32. #include <clib/alib_protos.h>
  33. #include <clib/reqtools_protos.h>
  34.  
  35. #include <pragmas/exec_pragmas.h>
  36. #include <pragmas/dos_pragmas.h>
  37. #include <pragmas/reqtools.h>
  38.  
  39.  
  40. #include "/common/types.h"
  41. #include "/common/errors.h"
  42. #include "/common/defines.h"
  43. #include "/common/structures.h"
  44. #include "/common/strings.h"
  45. #include "/common/files.h"
  46. #include "/common/release.h"
  47. // some forward defines
  48.  
  49. void __asm __saveds LIBstrNcpy(register __a0 UBYTE *dest,register __a1 UBYTE *source,register __d0 int chars);
  50. void __asm __saveds LIBHBBS_rterror(register __a0 char *str);
  51. BOOL __asm __saveds LIBAssignOK(register __a0 char *checkme );
  52. BOOL __asm __saveds LIBHBBS_AddCfgItem(register __a0 struct CfgFileData *cfgfile,register __a1 UBYTE *itemname,register __a2 UBYTE *params);
  53. struct List __asm __saveds *LIBHBBS_CreateList( void );
  54. void __asm __saveds LIBHBBS_DateStrFromTM(register __a0 UBYTE *datestr, register __a1 struct tm *timestruct);
  55. V_BOOL __asm __saveds LIBHBBS_AddCfgItemQuick(register __a0 struct CfgFileData *cfgfile,register __a1 char *ItemName, register __a2 char *Params);
  56. void  __asm __saveds  LIBHBBS_FlushConfig(register __a0 struct CfgFileData *cfgfile);
  57. BOOL __asm __saveds LIBPathOK(register __a0 char *str);
  58.  
  59. // needed libs..
  60.  
  61. struct DosLibrary *DOSBase=NULL;
  62. struct ExecBase *SysBase=NULL;
  63. struct ReqToolsBase *ReqToolsBase=NULL;
  64.  
  65. char *versionstr="$VER: HBBSCommon.library "RELEASE_STR;
  66.  
  67. // global variables.. (keep to a minimum..)
  68.  
  69. struct BBSGlobalData *BBSGlobal=NULL;
  70.  
  71. UBYTE *OPT_PRIV_LastUserNum="LastUserNum";
  72. UBYTE *OPT_PRIV_CallsEver="CallsEver";
  73.  
  74. char monthstr[12][4]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
  75.  
  76.  
  77. // actual functions..
  78.  
  79. void __asm __saveds LIBFreeStr(register __a0 char *str)
  80. {
  81.   if (str) FreeVec(str);
  82. }
  83.  
  84. char __asm __saveds *LIBDupStr(register __a0 char *str)
  85. {
  86.   char *newstr=NULL;
  87.   if (str)
  88.   {
  89.     if (newstr=(char *)AllocVec(strlen(str)+1,MEMF_PUBLIC))
  90.     {
  91.       newstr[0]=0;
  92.       strcpy(newstr,str);
  93.     }
  94.   }
  95.   return(newstr);
  96. }
  97.  
  98. char __asm __saveds *LIBFreeAndSet(register __a0 char **varname,register __a1 char *newstr)
  99. {
  100.   // this routines frees memory allocated to strings using strdup or
  101.   // and duplicates the string in newstr and sets varname to the newly allocated str
  102.  
  103.   if (*varname!=NULL)
  104.   {
  105.     LIBFreeStr(*varname);
  106.     *varname=NULL;
  107.   }
  108.  
  109.   if (newstr)
  110.   {
  111.     *varname=LIBDupStr(newstr);
  112.   }
  113.   return(*varname); // return varname if you want to test result..
  114. }
  115.  
  116.  
  117. V_BOOL __asm __saveds LIBCheckBoolean(register __a0 char *str)
  118. {
  119.   if (stricmp(str,"TRUE")==0 || stricmp(str,"ON")==0 || stricmp(str,"YES")==0)
  120.     return(TRUE);
  121.   else
  122.     return(FALSE);
  123. }
  124.  
  125.  
  126. // creates a new node with ln_Name set to a copy of str, and appends it to the list specified
  127.  
  128. V_ERROR __asm __saveds LIBNewStrNode(register __a0 char *str,register __a1 struct List *list)
  129. {
  130.   struct Node *NewNode;
  131.   V_ERROR retval=TYPE_MEMORY;
  132.  
  133.   if (NewNode=AllocVec(sizeof(struct Node),MEMF_PUBLIC))
  134.   {
  135.     if (NewNode->ln_Name=LIBDupStr(str))
  136.     {
  137.       AddTail(list,NewNode);
  138.       retval=ERR_NO_ERROR;
  139.     }
  140.     else
  141.     {
  142.       FreeVec(NewNode);
  143.     }
  144.   }
  145.   return(retval);
  146. }
  147.  
  148. void __asm __saveds LIBUpperCase(register __a0 char *str)
  149. {
  150.   // converts str into uppercase
  151.  
  152.   short loop;
  153.  
  154.   for (loop=0;str[loop];loop++) str[loop]=toupper(str[loop]);
  155. }
  156.  
  157. char __asm __saveds *LIBupcase(register __a0 char *str)
  158. {
  159.   // converts str into uppercase and returns a pointer to a new
  160.   // string.
  161.   // returns NULL if it fails.
  162.  
  163.   // dont forget to FreeStr() the output!
  164.  
  165.   char *outstr;
  166.   short loop;
  167.  
  168.   if (outstr=LIBDupStr(str))
  169.   {
  170.     for (loop=0;str[loop];loop++) outstr[loop]=toupper(str[loop]);
  171.   }
  172.   return(outstr);
  173. }
  174.  
  175. short __asm __saveds LIBposition(register __a0 char *substr,register __a1 char *str)
  176. {
  177.   // returns an character offset of a substring in a string
  178.   // this version is CASE SENSITIVE
  179.   // returns -1 if substring not found in the string
  180.  
  181.   char *whstr;
  182.   return((short)((whstr=strstr(str,substr)) ? (short)((LONG)whstr-(LONG)str) : -1));
  183. }
  184.  
  185. short __asm __saveds LIBiposition(register __a0 char *substr,register __a1 char *str)
  186. {
  187.   // returns an character offset of a substring in a string
  188.   // this version is CASE INSENSITIVE
  189.   // returns -1 if substring not found in the string
  190.   //      or -2 if memory allocation error
  191.  
  192.   short where=-2;
  193.   char *isubstr,*istr;
  194.  
  195.   if (isubstr=LIBupcase(substr))
  196.   {
  197.     if (istr=LIBupcase(str))
  198.     {
  199.       where=LIBposition(isubstr,istr);
  200.       LIBFreeStr(istr);
  201.     }
  202.     LIBFreeStr(isubstr);
  203.   }
  204.   return(where);
  205. }
  206.  
  207. void __asm __saveds LIBstrfcpy(register __a0 char *dest,register __a1 char *source,register __d0 int from)
  208. {
  209.   /*
  210.      copy all chars from "source" to "dest" starting at offset "from"
  211.      (kinda the reverse from strncpy() )
  212.    */
  213.   int loop=from,pos=0;
  214.   if (from<=strlen(source)-1)
  215.   {
  216.     while (source[loop])
  217.     {
  218.       dest[pos]=source[loop];
  219.       loop++;
  220.       pos++;
  221.     }
  222.   }
  223.   dest[pos]=0;
  224. }
  225.  
  226. void __asm __saveds LIBstripcr(register __a0 char *s)
  227. {
  228.   /* New Optimized Version 04-JAN-1996 */
  229.  
  230.   LONG Len;
  231.   if (s)
  232.   {
  233.     Len=strlen(s)-1; // set to point to last char in string 's'
  234.  
  235.     while (Len>=0 && (s[Len]=='\r' || s[Len]=='\n'))
  236.     {
  237.       s[Len--]=0; // string is now 1 char smaller, and overwrite the \r or \n with a null terminator
  238.     }
  239.   }
  240. }
  241.  
  242. /* old version, had problems with small strings!
  243. void __asm __saveds LIBstripcr(register __a0 char *s)
  244. {
  245.   // caters for \n or \r or \r\n or \n\r  :-)
  246.  
  247.   short sl;
  248.   sl=strlen(s);
  249.   if (s[sl-1]==10 || s[sl-1]==13) s[sl-1]=0;
  250.   sl=strlen(s);
  251.   if (s[sl-1]==10 || s[sl-1]==13) s[sl-1]=0;
  252.   // hmm ? how about a for next loop there ?  nah, bigger.. slower...
  253. }
  254. */
  255.  
  256.  
  257. UBYTE  __asm __saveds *LIBStripComments(register __a0 char *s)
  258. {
  259.   /* New Optimized Version 04-JAN-1996 */
  260.  
  261.   // returns a pointer to the start of the comments too..
  262.  
  263.   UBYTE *strptr;
  264.  
  265.   if (strptr=strchr(s,';'))
  266.   {
  267.     *strptr=0;
  268.     strptr++; //we've just killed the ';' so point to next char..
  269.   }
  270.   return(strptr);
  271. }
  272.  
  273. /* older version. allocated memory!!
  274. UBYTE  __asm __saveds *LIBStripComments(register __a0 char *s)
  275. {
  276. // returns a pointer to the start of the comments too..
  277.   int where;
  278.  
  279.   if ((where=LIBposition(";",s))>=0)
  280.   {
  281.     s[where]='\0';
  282.     return(&s[where+1]); // return pointer to character after the ; in the string
  283.   }
  284.   return(NULL);
  285. }
  286. */
  287.  
  288. void __asm __saveds LIBStripSpaces(register __a0 char *s)
  289. {
  290.   /* New Optimized Version 04-JAN-1996 */
  291.   /* this version only parses the string once, much nicer.. */
  292.  
  293.   LONG len=strlen(s)-1;
  294.  
  295.   // while the last char is a ' ', set it to a 0
  296.   while (len>=0 && s[len]==' ') s[len--]=0;  // cooler Kompakt coding! :-)
  297. }
  298.  
  299. /* old version, too slow, keeps parsing strings..
  300. void __asm __saveds LIBStripSpaces(register __a0 char *s)
  301. {
  302.   // while the last char is a ' ', set it to a 0
  303.   while (s[strlen(s)-1]==' ') s[strlen(s)-1]=0;  // Kompakt coding! :-)
  304. }
  305. */
  306. void __asm __saveds LIBreplace(register __a0 char *dest,register __a1 char *compare,register __a2 char *from,register __a3 char *to)
  307. {
  308.  
  309.   /*
  310.      replace all occurences of "from" in "compare" with "to" and store result in "dest"
  311.      (note: this is dead usefull!!!)
  312.  
  313.      e.g.  replace(dest,source,"Whops","Whoops!");
  314.  
  315.      compare and dest can be the same variable...
  316.  
  317.    */
  318.   int where;
  319.   char *mystring;
  320.  
  321.   if (mystring=LIBDupStr(compare))
  322.   {
  323.     strcpy(dest,"");
  324.     do
  325.     {
  326.       where=LIBposition(from,mystring);
  327.       if (where!=-1)
  328.       {
  329.         strncat(dest,mystring,where);                    /* copy first part of string */
  330.         strcat(dest,to);                                 /* add repeaced chars */
  331.         LIBstrfcpy(mystring,mystring,where+strlen(from));   /* copy rest of string  so we find first position of from */
  332.       }
  333.     } while (where!=-1);                                 /* keep doing until "from" is not found */
  334.     strcat(dest,mystring);                               /* add the rest of the string */
  335.     LIBFreeStr(mystring);
  336.   }
  337. }
  338.  
  339.  
  340. BOOL __asm __saveds LIBGetParams(register __a0 char *dest,register __a1 char *source)
  341. {
  342.   UBYTE *strptr;
  343.  
  344.   dest[0]=0;
  345.  
  346.   if (strptr=strchr(source,'='))
  347.   {
  348.     strcpy(dest,strptr+1);
  349.     return(TRUE);
  350.   }
  351.   return(FALSE);
  352. }
  353.  
  354. /* old version, shite...
  355. BOOL __asm __saveds LIBGetParams(register __a0 char *dest,register __a1 char *source)
  356. {
  357.   int where;
  358.  
  359.   dest[0]=0;
  360.  
  361. //  if ( ((where=LIBposition("=",source))!=-1) && (where!=(strlen(source)-1)) )
  362.  
  363.   if ((where=LIBposition("=",source))>=0)
  364.   {
  365.     LIBstrfcpy(dest,source,where+1);
  366.     return(TRUE);
  367.   }
  368.   return(FALSE);
  369. }
  370. */
  371.  
  372.  
  373. BOOL __asm __saveds LIBGetItem(register __a0 char *dest,register __a1 char *source)
  374. {
  375.   int loop=0;
  376.  
  377.   // increment start counter until we encounter a character that's not a space or tab
  378.  
  379.   while (source[loop]==' ' || source[loop]==8) loop++;
  380.  
  381.   while (source[loop] && source[loop]!='=') // not end of string && '=' ?
  382.   {
  383.     dest[loop]=source[loop];
  384.     loop++;
  385.   }
  386.   dest[loop]='\0';
  387.   if (dest[0]!=0) return(TRUE);
  388.  
  389.   return(FALSE);
  390. }
  391.  
  392. void __asm __saveds LIBGetNumber(register __a0 int *num,register __a1 char *item)
  393. {
  394.   int where;
  395.   char numstr[5];
  396.   for (where=strlen(item);isdigit(item[where-1]);where--);
  397.  
  398.   LIBstrfcpy(numstr,item,where);
  399.   *num=atoi(numstr);
  400. }
  401.  
  402.  
  403. ULONG  __asm __saveds LIBSafePutToPort(register __a0 struct Message *message, register __a1 STRPTR portname)
  404. {
  405.   struct MsgPort *port;
  406.   Forbid();
  407.   if (port=FindPort(portname))
  408.   {
  409.     PutMsg(port,message);
  410.   }
  411.   Permit();
  412.   return((ULONG)port);
  413. }
  414.  
  415. // new: if message you are sending has a reply port, it'll return a pointer to the replied
  416. // message, other wise it'll return 1.
  417. // it will ALWAYS return NULL if it fails to send the message tho..
  418.  
  419. struct Message __asm __saveds *LIBSendMessage(register __a0 struct Message *Msg,register __a1 char *MPortName)
  420. {
  421. //  BOOL waitforreply=(Msg->mn_ReplyPort) ? TRUE : FALSE;
  422.  
  423.   if (LIBSafePutToPort(Msg,MPortName))
  424.   {
  425. //  if (waitforreply)
  426.     if (Msg->mn_ReplyPort)
  427.     {
  428.       if (1L << Msg->mn_ReplyPort->mp_SigBit==Wait(1L << Msg->mn_ReplyPort->mp_SigBit))
  429.       {
  430.         return(GetMsg(Msg->mn_ReplyPort));
  431.       }
  432.     }
  433.     else return((struct Message *)1L);
  434.   }
  435.   return(NULL);
  436. }
  437.  
  438. V_BIGNUM __asm __saveds LIBCountListItems( register __a0 struct List *list)
  439. {
  440.   V_BIGNUM retval=0;
  441.   struct Node *node;
  442.  
  443.   if (list)
  444.   {
  445.     for (node = list->lh_Head ; node->ln_Succ ; node =node->ln_Succ)
  446.     {
  447.       retval++;
  448.     }
  449.   }
  450.   return(retval);
  451. }
  452.  
  453. void __asm __saveds LIBFreeStrList(register __a0 V_STRINGLIST strlist)
  454. {
  455.   // free all strings in a list and remove all nodes from the list.
  456.   // then free the nodes and the list itself..
  457.  
  458.   struct Node *node;
  459.   if (strlist)
  460.   {
  461.     while (strlist->lh_Head->ln_Succ)
  462.     {
  463.       node=strlist->lh_Head;
  464.       LIBFreeStr(node->ln_Name);
  465.       Remove(node);
  466.       FreeVec(node);
  467.     }
  468.     FreeVec(strlist);
  469.   }
  470. }
  471.  
  472. struct BBSGlobalData __asm __saveds *LIBHBBS_GimmeBBS( void )
  473. {
  474.   return(BBSGlobal);
  475. }
  476.  
  477. void  __asm __saveds  LIBHBBS_SetBBS(register __a0 struct BBSGlobalData *B)
  478. {
  479.   BBSGlobal=B;
  480. }
  481.  
  482. struct Node __asm __saveds  *LIBGetNode(register __a0 struct List *lh,register __d0 UWORD n)
  483. { // starts from 0, 0 being the first node in the list..
  484.   // thanks to the author of YAK for this and the next function..
  485.   struct Node *ln;
  486.  
  487.   for (ln = lh->lh_Head; n--; ln = ln->ln_Succ);
  488.   return ln;
  489. }
  490.  
  491. UWORD __asm __saveds LIBGetNodeNum(register __a0 struct List *lh,register __a1 struct Node *node)
  492. {
  493.   struct Node *ln;
  494.   UWORD i;
  495.  
  496.   for (i = 0, ln = lh->lh_Head; ln != node; ln = ln->ln_Succ, i++);
  497.   return i;
  498. }
  499.  
  500. struct NodeData  __asm __saveds *LIBHBBS_NodeDataPtr(register __d0 short nodenum)
  501. {
  502.   struct NodeData *nd;
  503.  
  504.   for (nd = (struct NodeData *)BBSGlobal->NodeList->lh_Head ; nd->node.ln_Succ ; nd =(struct NodeData *) nd->node.ln_Succ)
  505.   {
  506.     if (nd->NodeNum==nodenum) return(nd);
  507.   }
  508.   return(NULL);
  509. }
  510.  
  511.  
  512. V_ERROR __asm __saveds LIBHBBS_LogError(register __a0 V_STRING filename,register __d0 V_ERROR errnum,register __a1 V_STRING string,register __d1 V_ERROR errtype)
  513. {
  514.   // this function returns the parameter errnum supplied and unmodified.
  515.   BPTR FH;
  516.   V_STRING errstr;
  517.   struct tm *tp;
  518.   long t;
  519.  
  520.   if (filename)
  521.   {
  522.     if (FH=Open(filename,MODE_READWRITE))
  523.     {
  524.       Seek(FH,0,OFFSET_END);
  525.       if (errstr=AllocVec(BIG_STR,MEMF_PUBLIC))
  526.       {
  527.         time(&t);
  528.         tp=localtime(&t);
  529.         sprintf(errstr,"%s %s: ",asctime(tp),TYPE_STR[errtype]);
  530.  
  531.         Write(FH,errstr,strlen(errstr)); // don't care if it fails.. (could be diskfull :-)
  532.  
  533.         switch(errnum)
  534.         {
  535.           case ERR_ERROR_OPENING:
  536.             sprintf(errstr,"Error opening the file -> %s",string);
  537.             break;
  538.           case ERR_ERROR_READING:
  539.             sprintf(errstr,"Error reading the file -> %s",string);
  540.             break;
  541.           case ERR_ERROR_WRITING:
  542.             sprintf(errstr,"Error writing the file -> %s",string);
  543.             break;
  544.           case ERR_NODESETTINGS:
  545.             strcpy(errstr,"NodeLocal File Error");
  546.             break;
  547.           case ERR_GENERAL:
  548.             strcpy(errstr,string);
  549.             break;
  550.           case ERR_DOORTIMEOUT:
  551.             sprintf(errstr,"Timout Occured When Loading Door -> %s",string);
  552.             break;
  553.           default:
  554.             sprintf(errstr,"Unknown Error!");
  555.             break;
  556.         }
  557.         Write(FH,errstr,strlen(errstr));
  558.  
  559.         Write(FH,"\n",1);
  560.  
  561.         FreeVec(errstr);
  562.       }
  563.       Close(FH);
  564.     }
  565.   }
  566.   return(errnum);
  567. }
  568.  
  569. /*
  570.  
  571. // lets play spot the bug that cuases this routine to crash the system..
  572. // 5 quid goes to the person the finds the problem!!
  573.  
  574. struct CfgFileData __asm __saveds *LIBHBBS_LoadConfig(register __a0 UBYTE *filename,register __d0 ULONG Flags)
  575. {
  576.   // New Optimized Version 04-JAN-1996
  577.  
  578.   BPTR FH;
  579.   LONG found=0;
  580.   UBYTE buffer[BIG_STR+1];
  581.   UBYTE ItemName[BIG_STR+1];
  582.   UBYTE Params[BIG_STR+1];
  583.   struct CfgFileData *cfgfile=NULL;
  584.   struct CfgItemData *node=NULL;
  585.   if (LIBPathOK(filename))
  586.   {
  587.     // create and init our CfgFileData structure..
  588.  
  589.     if (cfgfile=AllocVec(sizeof(struct CfgFileData),MEMF_PUBLIC|MEMF_CLEAR))
  590.     {
  591.       cfgfile->filename=LIBDupStr(filename);
  592.  
  593.       if (cfgfile->ItemsList=LIBHBBS_CreateList())
  594.       {
  595.         if (FH=Open(filename,MODE_OLDFILE))
  596.         {
  597.           while (FGets(FH,buffer,BIG_STR))
  598.           {
  599.             LIBstripcr(buffer);
  600.             ItemName[0]=0;
  601.             Params[0]=0;
  602.  
  603.             LIBStripComments(buffer);
  604.  
  605.             LIBStripSpaces(buffer);
  606.  
  607.             if (LIBGetItem(ItemName,buffer))
  608.             {
  609.               if (LIBGetParams(Params,buffer))
  610.               {
  611.  
  612.                 if (node=AllocVec(sizeof(struct CfgItemData),MEMF_PUBLIC))
  613.                 {
  614.                   node->node.ln_Name=LIBDupStr(ItemName);  // *C* add errorchecking..
  615.                   node->Params=LIBDupStr(Params);
  616.                   AddTail(cfgfile->ItemsList,(struct Node*)node);
  617.                   found++;
  618.                 }
  619.  
  620. //                if (LIBHBBS_AddCfgItemQuick(cfgfile,ItemName,Params))
  621. //                {
  622. //                  found++;
  623. //                }
  624.               }
  625.             }
  626.           }
  627.           Close(FH);
  628.         }
  629.       }
  630.       if (!found)
  631.       {
  632.         LIBHBBS_FlushConfig(cfgfile);
  633.         cfgfile=NULL;
  634.       }
  635.     }
  636.   }
  637.  
  638.  
  639.   return(cfgfile);
  640. }
  641. */
  642.  
  643. struct CfgFileData __asm __saveds *LIBHBBS_LoadConfig(register __a0 UBYTE *filename,register __d0 ULONG Flags)
  644. {
  645.   BPTR FH;
  646.   struct FileInfoBlock *FIB;
  647.   LONG nr;
  648.   UBYTE *Data;
  649.   ULONG Length;
  650.  
  651.   V_BOOL done,nearlydone;
  652.   LONG filepos=0,bufferpos,found=0;
  653.   V_STRING buffer;
  654.   V_STRING ItemName;
  655.   V_STRING Params;
  656.   struct CfgItemData *node;
  657.   struct CfgFileData *cfgfile=NULL;
  658.  
  659.   if (FH=Open(filename,MODE_OLDFILE))
  660.   {
  661.     if (cfgfile=AllocVec(sizeof(struct CfgFileData),MEMF_PUBLIC|MEMF_CLEAR))
  662.     {
  663.  
  664.       if (FIB=(struct FileInfoBlock *)AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
  665.       {
  666.         ExamineFH(FH,FIB);
  667.         Length=FIB->fib_Size;
  668.         if (Data=AllocVec(Length,MEMF_PUBLIC))
  669.         {
  670.           if ((nr=Read(FH,Data,Length))!=Length)
  671.           {
  672.             LIBHBBS_LogError(BBSGlobal->ErrorLogFile,ERR_ERROR_READING,filename,TYPE_CRITICAL);
  673.           }
  674.           else
  675.           {
  676.             if (cfgfile->ItemsList=LIBHBBS_CreateList())
  677.             {
  678.               buffer=AllocVec(BIG_STR,MEMF_PUBLIC);
  679.               ItemName=AllocVec(BIG_STR,MEMF_PUBLIC);
  680.               Params=AllocVec(BIG_STR,MEMF_PUBLIC);
  681.               if (buffer && ItemName && Params)
  682.               {
  683.                 do
  684.                 {
  685.                   bufferpos=0;
  686.                   done=FALSE;
  687.                   nearlydone=FALSE; // :-) love those variable names! :-)
  688.                   do
  689.                   {
  690.                     if (Data[filepos]=='\r' || Data[filepos]=='\n')
  691.                     {
  692.                       nearlydone=TRUE;
  693.                       filepos++;
  694.                     }
  695.                     else
  696.                     {
  697.                       if (nearlydone)
  698.                       {
  699.                         done=TRUE;
  700.                       }
  701.                       else
  702.                       {
  703.                         buffer[bufferpos]=Data[filepos];
  704.                         filepos++;
  705.                         bufferpos++;
  706.                       }
  707.                     }
  708.                   } while (filepos<Length && !done && bufferpos<BIG_STR-2); // 1 for null and 1 more cos we still have to add the null
  709.                   buffer[bufferpos]=0;
  710.  
  711.                   ItemName[0]=0; // null terminate both strings..
  712.                   Params[0]=0;
  713.  
  714.                   if (!(Flags & LCFG_NOSTRIPCOMMENTS)) LIBStripComments(buffer);
  715.                   if (!(Flags & LCFG_NOSTRIPSPACES))   LIBStripSpaces(buffer);
  716.  
  717.                   if (LIBGetItem(ItemName,buffer))
  718.                   {
  719.                     if (LIBGetParams(Params,buffer))
  720.                     {
  721.                       if (node=AllocVec(sizeof(struct CfgItemData),MEMF_PUBLIC))
  722.                       {
  723.                         node->node.ln_Name=LIBDupStr(ItemName);  // *C* add errorchecking..
  724.                         node->Params=LIBDupStr(Params);
  725.                         AddTail(cfgfile->ItemsList,(struct Node*)node);
  726.                         found++;
  727.                       }
  728.                     }
  729.                   }
  730.                 } while (filepos<Length);
  731.               }
  732.               if (Params)     FreeVec(Params);
  733.               if (ItemName)   FreeVec(ItemName);
  734.               if (buffer)     FreeVec(buffer);
  735.             }
  736.           }
  737.           FreeVec(Data);
  738.         }
  739.         FreeVec(FIB);
  740.       }
  741.       if (found)
  742.       {
  743.         cfgfile->filename=LIBDupStr(filename);
  744.       }
  745.       else
  746.       {
  747.         LIBHBBS_FlushConfig(cfgfile);
  748.         cfgfile=NULL; // just to make sure.. *C* ?? needed ?
  749.       }
  750.     }
  751.     Close(FH);
  752.   }
  753.   return(cfgfile);
  754. }
  755.  
  756. void  __asm __saveds  LIBHBBS_FlushConfig(register __a0 struct CfgFileData *cfgfile)
  757. {
  758.   struct CfgItemData *node;
  759.   if (cfgfile)
  760.   {
  761.     while ((cfgfile->ItemsList) && (cfgfile->ItemsList->lh_Head->ln_Succ))
  762.     {
  763.       node=(struct CfgItemData *)cfgfile->ItemsList->lh_Head;
  764.  
  765.       LIBFreeStr(node->node.ln_Name);
  766.       LIBFreeStr(node->Params);
  767.       Remove((struct Node *)node);
  768.       FreeVec(node);
  769.     }
  770.     FreeVec(cfgfile->ItemsList);
  771.     LIBFreeStr(cfgfile->filename);
  772.     FreeVec(cfgfile);
  773.   }
  774. }
  775.  
  776. V_BOOL __asm __saveds LIBHBBS_SaveConfig(register __a0 struct CfgFileData *cfgfile)
  777. {
  778.  
  779.   // returns TRUE on successful completion.
  780.  
  781.   BPTR FH;
  782.   struct CfgItemData *node;
  783.   char outstr[BIG_STR];
  784.  
  785.   if (LIBAssignOK(cfgfile->filename))
  786.   {
  787.     if (FH=Open(cfgfile->filename,MODE_NEWFILE))
  788.     {
  789.       for (node = (struct CfgItemData*)cfgfile->ItemsList->lh_Head ; node->node.ln_Succ ; node =(struct CfgItemData *)node->node.ln_Succ)
  790.       {
  791.         sprintf(outstr,"%s=%s\n",node->node.ln_Name,node->Params);
  792.         Write(FH,outstr,strlen(outstr));
  793.       }
  794.       Close(FH);
  795.       return(TRUE);
  796.     }
  797.   }
  798.   return(FALSE);
  799. }
  800.  
  801. struct CfgItemData __asm __saveds *LIBHBBS_GetCfgNode(register __a0 struct CfgFileData *cfgfile,register __a1 V_STRING optionstr)
  802. {
  803.  
  804.   struct CfgItemData *Item;
  805.  
  806.   for (Item = (struct CfgItemData *)cfgfile->ItemsList->lh_Head ; Item->node.ln_Succ ; Item =(struct CfgItemData *) Item->node.ln_Succ)
  807.   {
  808.     if (stricmp(optionstr,Item->node.ln_Name)==0)
  809.     {
  810.       return(Item);
  811.     }
  812.   }
  813.   return(NULL);
  814. }
  815.  
  816. V_SMALLNUM  __asm __saveds LIBHBBS_GetSetting(register __a0 struct CfgFileData *cfgfile,register __a1 void **result,register __d0 V_FLAGS optiontype,register __a2 V_STRING optionstr,register __d1 V_BOOL multi)
  817. {
  818.   // returns the amount of items found (1 for non multi, >0 for multi, 0 for none)
  819.  
  820.   V_SMALLNUM found=0;
  821.   V_STRING CompareStr;
  822.   struct Node *node;
  823.   struct CfgItemData *Item;
  824.  
  825.   // allocate a big string for comparing the strings..
  826.   if (CompareStr=AllocVec(BIG_STR,MEMF_PUBLIC))
  827.   {
  828.     // parse list..
  829.     for (Item = (struct CfgItemData *)cfgfile->ItemsList->lh_Head ; Item->node.ln_Succ ; Item =(struct CfgItemData *) Item->node.ln_Succ)
  830.     {
  831.       if (multi==OPT_MULTI)
  832.       {
  833.         sprintf(CompareStr,"%s_%d",optionstr,found+1);
  834.       }
  835.  
  836.       if ((multi==OPT_SINGLE) && (stricmp(optionstr,Item->node.ln_Name)==0) ||
  837.          (multi==OPT_MULTI) && (stricmp(CompareStr,Item->node.ln_Name)==0))
  838.       {
  839.         switch(optiontype)
  840.         {
  841.           case VTYPE_STRING:
  842.           case VTYPE_DATE:
  843.             if (*result!=NULL) LIBFreeStr(*result);
  844.             *result=(V_STRING *)LIBDupStr(Item->Params);
  845.             found++;
  846.             break;
  847.           case VTYPE_PATH:
  848.             if (*result!=NULL) LIBFreeStr(*result);
  849.             if (*result=(V_STRING)AllocVec(strlen(Item->Params)+1,MEMF_CLEAR|MEMF_PUBLIC))
  850.             {
  851.               strcpy((V_STRING)*result,Item->Params);
  852.               if ((Item->Params[strlen(Item->Params)-1]!='/') && (Item->Params[strlen(Item->Params)-1]!=':'))
  853.               {
  854.                 strcat((V_STRING)*result,"/");
  855.               }
  856.               found++;
  857.  
  858.             }
  859.             break;
  860.           case VTYPE_BOOL:
  861.             *result=(V_BOOL *)LIBCheckBoolean(Item->Params);
  862.             found++;
  863.             break;
  864.           case VTYPE_BIGNUM:
  865.           case VTYPE_TIME:
  866.             *result=(V_BIGNUM *)atoi(Item->Params);
  867.             found++;
  868.             break;
  869.           case VTYPE_WORD:
  870.             *result=(WORD *)atoi(Item->Params);
  871.             found++;
  872.             break;
  873.           case VTYPE_SMALLNUM:
  874.             *result=(V_SMALLNUM *)atoi(Item->Params);
  875.             found++;
  876.             break;
  877.           case VTYPE_STRINGLIST:
  878.           case VTYPE_PATHLIST:
  879.             // free existing stringlist if present
  880.  
  881.             if ((found==0) && (*result))
  882.             {
  883.               LIBFreeStrList((V_STRINGLIST)*result);
  884.             }
  885.             if (!(*result))
  886.             {
  887.               if(*result=AllocVec(sizeof (struct List),MEMF_PUBLIC))
  888.               {
  889.                 NewList((struct List*)*result);
  890.               }
  891.             }
  892.             if (*result) // allocated new list ok ?
  893.             {
  894.               if (node=AllocVec(sizeof(struct Node),MEMF_PUBLIC))
  895.               {
  896.                 if (optiontype==VTYPE_PATHLIST)
  897.                 {
  898.                   if (node->ln_Name=AllocVec(strlen(Item->Params)+1,MEMF_CLEAR|MEMF_PUBLIC))
  899.                   {
  900.                     strcpy(node->ln_Name,Item->Params);
  901.                     if ((node->ln_Name[strlen(node->ln_Name)-1]!=':') && (node->ln_Name[strlen(node->ln_Name)-1]!='/'))
  902.                     {
  903.                       strcat(node->ln_Name,"/");
  904.                     }
  905.                   }
  906.                 }
  907.                 else
  908.                 {
  909.                   node->ln_Name=LIBDupStr(Item->Params);
  910.                 }
  911.  
  912.                 if (!(node->ln_Name))
  913.                 {
  914.                   FreeVec(node);
  915.                 }
  916.                 else
  917.                 {
  918.                   AddTail((struct List *)*result,node);
  919.  
  920.                   found++;
  921.  
  922.                   // go to start of list again or we might miss out something..
  923.                   Item = (struct CfgItemData *)cfgfile->ItemsList->lh_Head;
  924.                 }
  925.  
  926.               }
  927.             }
  928.         }
  929.       }
  930.     }
  931.     FreeVec(CompareStr);
  932.   }
  933.   return(found);
  934. }
  935.  
  936. struct CfgFileData __asm __saveds *LIBHBBS_CreateConfig(register __a0 UBYTE *filename)
  937. {
  938.   struct CfgFileData *newcfg;
  939.  
  940.   if (newcfg=(struct CfgFileData *)AllocVec(sizeof(struct CfgFileData),MEMF_PUBLIC|MEMF_CLEAR))
  941.   {
  942.     if (newcfg->ItemsList=(struct List *)AllocVec(sizeof(struct List ),MEMF_PUBLIC))
  943.     {
  944.       NewList(newcfg->ItemsList);
  945.       newcfg->filename=LIBDupStr(filename);  // *C* add errorchecking..
  946.     }
  947.     else
  948.     {
  949.       FreeVec(newcfg);
  950.       newcfg=NULL;
  951.     }
  952.   }
  953.   return(newcfg);
  954. }
  955.  
  956. BOOL __asm __saveds LIBHBBS_RemoveCfgItem(register __a0 struct CfgFileData *cfgfile,register __a1 UBYTE *itemname)
  957. {
  958.   struct CfgItemData *node;
  959.   BOOL Removed=FALSE;
  960.   char *match;
  961.  
  962.   if (match=AllocVec((strlen(itemname)*2)+2,MEMF_PUBLIC))
  963.   {
  964.     if (cfgfile && cfgfile->ItemsList)
  965.     {
  966.       for (node = (struct CfgItemData*)cfgfile->ItemsList->lh_Head ;(node->node.ln_Succ) ; node =(struct CfgItemData *)node->node.ln_Succ)
  967.       {
  968.         ParsePatternNoCase(itemname,match,(strlen(itemname)*2)+2);
  969.         if (MatchPatternNoCase(match,node->node.ln_Name))
  970.         {
  971.           Remove((struct Node*)node);
  972.           LIBFreeStr(node->Params);
  973.           LIBFreeStr(node->node.ln_Name);
  974.           FreeVec(node);
  975.           // go to start of list again..
  976.           node=node = (struct CfgItemData*)cfgfile->ItemsList->lh_Head;
  977.           Removed=TRUE;
  978.         }
  979.       }
  980.     }
  981.     FreeVec(match);
  982.   }
  983.   return(Removed);
  984. }
  985.  
  986. BOOL __asm __saveds LIBHBBS_AddCfgItem(register __a0 struct CfgFileData *cfgfile,register __a1 UBYTE *itemname,register __a2 UBYTE *params)
  987. {
  988.   struct CfgItemData *node;
  989.   BOOL Done=FALSE;
  990.  
  991. /*
  992.   char *offset,*remstr;
  993.   short loop;
  994. */
  995.   if (cfgfile && cfgfile->ItemsList)
  996.   {
  997.     // check to see if itemname is already there..
  998.  
  999.     LIBHBBS_RemoveCfgItem(cfgfile,itemname);
  1000.  
  1001. /*
  1002.  * Unsed bit of usefull code, was origonally going to make it so that when you start
  1003.  * adding items of a list to a config items list it removed all the parts of the old
  1004.  * list first..  but decided not to do it this way (at all) but left this bit of code
  1005.  * cos it might be usefull.. :-)
  1006.  *
  1007.     if (offset=strrchr(itemname,'_'))
  1008.     {
  1009.       offset++;
  1010.       if (offset[0]!=0)
  1011.       {
  1012.         if (isdigit(offset[0]))
  1013.         {
  1014.           loop=1;
  1015.           while (isdigit(offset[loop]))
  1016.           {
  1017.             loop++;
  1018.           }
  1019.  
  1020.           if (offset[loop]==0)
  1021.           {
  1022.             if (remstr=AllocVec(strlen(itemname)+2,MEMF_PUBLIC))
  1023.             {
  1024.               LIBstrNcpy(remstr,itemname,offset-itemname);
  1025.               strcat(remstr,"#?");
  1026.  
  1027.               LIBHBBS_RemoveCfgItem(cfgfile,remstr);
  1028.  
  1029.               FreeVec(remstr);
  1030.             }
  1031.           }
  1032.         }
  1033.       }
  1034.     }
  1035. */
  1036.  
  1037.     if (node=AllocVec(sizeof(struct CfgItemData),MEMF_PUBLIC))
  1038.     {
  1039.       node->node.ln_Name=LIBDupStr(itemname);  // *C* add errorchecking..
  1040.       node->Params=LIBDupStr(params);
  1041.       AddTail(cfgfile->ItemsList,(struct Node*)node);
  1042.       Done=TRUE;
  1043.     }
  1044.   }
  1045.   return(Done);
  1046. }
  1047.  
  1048. void __asm __saveds LIBHBBS_ResetNodeData(register __a0 struct NodeData *node)
  1049. {
  1050.   // this function is called a) when a node is initialised
  1051.   // and b) when a node shuts down. (everything is freed first tho..
  1052.  
  1053.   node->LoginType=LOGIN_NONE;
  1054.   node->OnlineStatus=OS_OFFLINE; // node program sets this to ONLINE or OFFLINE
  1055.                               // this shot be used in all door programs to determine
  1056.                               // carrier status (even for local logins..)
  1057.   node->User.Valid=FALSE;
  1058.   node->User.ConfAcs.Name=NULL;
  1059.   node->NodeFlags=0L;
  1060.   node->Status=STAT_CLOSED;
  1061.   node->NodePort=NULL;
  1062.   node->SettingsOpen=FALSE;
  1063.   node->InformationOpen=FALSE;
  1064.   node->ConOK=FALSE;
  1065.   node->SerOK=FALSE;
  1066.   node->SerOPEN=FALSE;
  1067.   node->SerWaiting=FALSE;
  1068.   node->ConWaiting=FALSE;
  1069.   node->ReplyPort=NULL;
  1070.   node->RequestShutdown=FALSE;
  1071.   node->ActiveDoor=NULL;
  1072.   node->DoorsRunning=0;
  1073.   node->DoorReturn[0]=0;
  1074.   node->CurrentLine[0]=0;
  1075.   node->TransferringFile=FALSE;
  1076.   node->TaggedFiles=0;
  1077.   node->AllowLogins=TRUE;
  1078.   strcpy(node->Action,"Initialising!"); // max 29 chars!
  1079.   node->ConnectBaud[0]=0; // max 8 chars..
  1080.  
  1081.   node->Current_Last_Callers=0;
  1082.   node->Current_Last_Uploads=0;
  1083.   node->Current_Last_Downloads=0;
  1084.   node->Current_Last_PWFails=0;
  1085.   node->Current_Last_Carrier=0;
  1086.   node->Current_Last_Pagers=0;
  1087.  
  1088.   // *C* make sysop definable..
  1089.   node->Max_Last_Callers=10;
  1090.   node->Max_Last_Uploads=10;
  1091.   node->Max_Last_Downloads=10;
  1092.   node->Max_Last_PWFails=10;
  1093.   node->Max_Last_Carrier=10;
  1094.   node->Max_Last_Pagers=10;
  1095. }
  1096.  
  1097. void  __asm __saveds LIBHBBS_rterror(register __a0 char *str)
  1098. {
  1099.   rtEZRequestTags(str,str_OK,NULL,NULL,RTGS_Flags, GSREQF_CENTERTEXT,TAG_END);
  1100. }
  1101.  
  1102.  
  1103. LONG  __asm __saveds LIBHBBS_RunDOSCMD(register __a0 char *command,register __d0 BOOL ASYNC)
  1104. {
  1105.   LONG retval;
  1106.   char newcmd[BIG_STR],consolename[BIG_STR];
  1107.  
  1108.   static ULONG sysargs[] =
  1109.   {
  1110.     SYS_Input,NULL,
  1111.     SYS_Output,NULL,
  1112.     SYS_Asynch,TRUE,
  1113.     SYS_UserShell,TRUE,
  1114.     NP_Priority,0L,
  1115.     TAG_DONE
  1116.   };
  1117.   BPTR outputfile=NULL;
  1118.  
  1119.   sysargs[5]=ASYNC;
  1120.  
  1121.   LIBreplace(newcmd,command,"@S@",BBSGlobal->ScreenInfo.PubScreenName);
  1122.   LIBreplace(consolename,str_CONSOLE,"@S@",BBSGlobal->ScreenInfo.PubScreenName);
  1123.  
  1124. //  if (!strchr(newcmd,'>') && !strchr(newcmd,'<'))
  1125. //  {
  1126.     if (outputfile = Open(consolename,MODE_OLDFILE))
  1127.     {
  1128.       sysargs[1]=(ULONG)outputfile;
  1129.     }
  1130. //  }
  1131.   retval=SystemTagList(newcmd,(struct TagItem *)sysargs);
  1132.   if (!ASYNC && outputfile) Close(outputfile); // close window if not async
  1133.  
  1134.   return(retval);
  1135.  
  1136.   // *C* perhaps add a routine to close async'ed windows after 5 mins ??
  1137. }
  1138.  
  1139. void __asm __saveds LIBHBBS_DoErrorMessage(register __d0 ULONG num,register __d1 ULONG node,register __a0 char *errstr)
  1140. {
  1141.   char *str;
  1142.   int len=20; // 20 extra chars should be ok for the numbers
  1143.  
  1144.   if (errstr) len+=strlen(errstr);
  1145.  
  1146.   if (str=AllocVec(len+strlen(PRG_ERRORMESSAGE),MEMF_PUBLIC))
  1147.   {
  1148.     sprintf(str,"%s %d %d ",PRG_ERRORMESSAGE,num,node);
  1149.     if (errstr) strcat(str,errstr);
  1150.     LIBHBBS_RunDOSCMD(str,TRUE); // *C* false ?
  1151.     FreeVec(str);
  1152.   }
  1153. }
  1154.  
  1155. void __asm __saveds LIBcvtucase(register __a0  char *str)
  1156. {
  1157.   int loop;
  1158.   for (loop=0;str[loop]!=0;loop++)
  1159.   {
  1160.     str[loop]=toupper(str[loop]);
  1161.   }
  1162. }
  1163.  
  1164. BOOL __asm __saveds LIBAssignOK(register __a0 char *checkme )
  1165. {
  1166.   struct DosList      *DosList;
  1167.   struct DeviceNode   *DevNode;
  1168.   UBYTE           *Pointer;
  1169.   char string[32]="",cmpstring[32]="";
  1170.   int loop;
  1171.   BOOL found=FALSE;
  1172.  
  1173.   if (strnicmp(checkme,"Progdir:",8)==0)
  1174.   {
  1175.     found=TRUE;
  1176.   }
  1177.   else
  1178.   {
  1179.  
  1180.     for (loop = 0 ; checkme[loop]!=0 && checkme[loop]!=':' && checkme[loop]!='/' ; loop++);
  1181.     LIBstrNcpy(cmpstring,checkme,loop);// +1); // +1 cos we WANT the ':'
  1182.     LIBcvtucase(cmpstring);
  1183.     DosList = LockDosList(LDF_ALL|LDF_READ);
  1184.     while((DosList = NextDosEntry(DosList,LDF_ALL|LDF_READ)) && !found)
  1185.     {
  1186.       DevNode = (struct DeviceNode *)DosList;
  1187.  
  1188.       // assign or volume ?
  1189.       if (DevNode->dn_Type==DLT_DIRECTORY || DevNode->dn_Type==DLT_DEVICE || DevNode->dn_Type==DLT_VOLUME)
  1190.       {
  1191.         Pointer = (UBYTE *)BADDR(DevNode -> dn_Name);
  1192.         if (Pointer[0])
  1193.         {
  1194.           for(loop = 0 ; loop < Pointer[0] ; loop++)
  1195.                             string[loop] = Pointer[loop + 1];
  1196.  
  1197.           string[Pointer[0]]   = 0; /* terminate string */
  1198.   //        strcat(string,":");
  1199.           LIBcvtucase(string);
  1200.           if (strcmp(cmpstring,string)==0) found=TRUE;
  1201.         }
  1202.       }
  1203.     }
  1204.     UnLockDosList(LDF_ALL|LDF_READ);
  1205.   }
  1206.   return(found);
  1207. }
  1208.  
  1209. BOOL __asm __saveds LIBHBBS_InitCommon( void )
  1210. {
  1211.   SysBase = *(struct ExecBase **) 4L;
  1212.   if (DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", 0))
  1213.   {
  1214.     if (ReqToolsBase = (struct ReqToolsBase *) OpenLibrary (REQTOOLSNAME, REQTOOLSVERSION))
  1215.     return(TRUE);
  1216.   }
  1217.   return(FALSE);
  1218. }
  1219.  
  1220. void __asm __saveds LIBHBBS_CleanUpCommon( void )
  1221. {
  1222.   if (ReqToolsBase) CloseLibrary ((struct Library *)ReqToolsBase);
  1223.   if (DOSBase) CloseLibrary ((struct Library *) DOSBase);
  1224. }
  1225.  
  1226. struct TimerData __asm __saveds *LIBSubmitTimer(register __a0 struct TimerSetupData *TSD, register __d0 ULONG Seconds,register __d1 ULONG MicroSeconds )
  1227. {
  1228.   struct TimerData *TD=NULL;
  1229.  
  1230.   if (TSD)
  1231.   {
  1232.     if (TD=(struct TimerData*)AllocVec(sizeof(struct TimerData),MEMF_PUBLIC))
  1233.     {
  1234.       // copy fields accross from our blank timer IO request
  1235.       // that was initialised by InitTimer();
  1236.  
  1237.       //      Source             Dest   Size
  1238.       CopyMem(TSD->BlankTimerIO,&TD->TR,sizeof(struct timerequest));
  1239.  
  1240.       TD->TR.tr_time.tv_secs   = Seconds;
  1241.       TD->TR.tr_time.tv_micro   = MicroSeconds;
  1242.       AddHead(TSD->TimerList,(struct Node*)TD);
  1243.  
  1244.       SendIO((struct IORequest *)&TD->TR);
  1245.     }
  1246.   }
  1247.   return(TD);
  1248. }
  1249.  
  1250. void __asm __saveds LIBAbortTimer(register __a0 struct TimerSetupData *TSD, register __a1 struct TimerData *CTD)
  1251. {
  1252.   struct TimerData *TD;
  1253.  
  1254.   if (CTD)
  1255.   {
  1256.     for (TD = (struct TimerData *)TSD->TimerList->lh_Head ; TD->node.ln_Succ ; TD =(struct TimerData *) TD->node.ln_Succ)
  1257.     {
  1258.       if (TD==CTD)
  1259.       {
  1260.         AbortIO((struct IORequest *)&CTD->TR);
  1261.         WaitIO((struct IORequest *)&CTD->TR);
  1262.         Remove((struct Node*)CTD);
  1263.         FreeVec(CTD);
  1264.         // TD is now null so we dont wat to reference it again so return from the func..
  1265.         return;
  1266.       }
  1267.     }
  1268.   }
  1269. }
  1270.  
  1271. BOOL __asm __saveds LIBCheckTimer(register __a0 struct TimerSetupData *TSD, register __a1 struct TimerData *CTD)
  1272. {
  1273.   struct TimerData *TD;
  1274.  
  1275.   for (TD = (struct TimerData *)TSD->TimerList->lh_Head ; TD->node.ln_Succ ; TD =(struct TimerData *) TD->node.ln_Succ)
  1276.   {
  1277.     if (TD==CTD)
  1278.     {
  1279.       if (CheckIO((struct IORequest *)&CTD->TR))
  1280.       {
  1281.         WaitIO((struct IORequest *)&CTD->TR);
  1282.         Remove((struct Node*)CTD);
  1283.         FreeVec(CTD);
  1284.         return(TRUE);
  1285.       }
  1286.     }
  1287.   }
  1288.   return(FALSE);
  1289. }
  1290.  
  1291. void __asm __saveds LIBCleanupTimer( register __a0 struct TimerSetupData *TSD )
  1292. {
  1293.   struct TimerData *TD;
  1294.  
  1295.   if (TSD)
  1296.   {
  1297.     if (TSD->TimerPort)
  1298.     {
  1299.       if (TSD->BlankTimerIO)
  1300.       {
  1301.         if (TSD->TimerOpen)
  1302.         {
  1303.           if (TSD->TimerList)
  1304.           {
  1305.             // remove all outstanding io requests..
  1306.             while ((struct TimerData *)TSD->TimerList->lh_Head->ln_Succ)
  1307.             {
  1308.               TD=(struct TimerData *)TSD->TimerList->lh_Head;
  1309.               AbortIO((struct IORequest *)&TD->TR);
  1310.               WaitIO((struct IORequest *)&TD->TR);
  1311.               Remove((struct Node*)TD);
  1312.               FreeVec(TD);
  1313.             }
  1314.             FreeVec(TSD->TimerList);
  1315.           }
  1316.           CloseDevice((struct IORequest *) TSD->BlankTimerIO);
  1317.           TSD->TimerOpen=FALSE;
  1318.         }
  1319.         DeleteExtIO((struct IORequest *) TSD->BlankTimerIO);
  1320.       }
  1321.       DeleteMsgPort(TSD->TimerPort);
  1322.     }
  1323.     FreeVec(TSD);
  1324.   }
  1325. }
  1326.  
  1327. struct TimerSetupData __asm __saveds *LIBInitTimer( void )
  1328. {
  1329.   struct TimerSetupData *TSD;
  1330.  
  1331.   if (TSD=AllocVec(sizeof(struct TimerSetupData),MEMF_PUBLIC))
  1332.   {
  1333.     TSD->TimerOpen=FALSE;
  1334.     if (TSD->TimerPort = CreateMsgPort())
  1335.     {
  1336.       if (TSD->BlankTimerIO = (struct timerequest *) CreateExtIO(TSD->TimerPort,sizeof(struct timerequest)) )
  1337.       {
  1338.         if (OpenDevice( TIMERNAME, UNIT_VBLANK,(struct IORequest *) TSD->BlankTimerIO, 0L)==0) // success ?
  1339.         {
  1340.           TSD->TimerOpen=TRUE;
  1341.           TSD->BlankTimerIO->tr_node.io_Command = TR_ADDREQUEST;
  1342.           if (TSD->TimerList=AllocVec(sizeof(struct List),MEMF_PUBLIC))
  1343.           {
  1344.             NewList((struct List *)TSD->TimerList);
  1345.             return(TSD);
  1346.           }
  1347.         }
  1348.       }
  1349.     }
  1350.     LIBCleanupTimer(TSD);
  1351.   }
  1352.   return(NULL);
  1353. }
  1354.  
  1355. BOOL __asm __saveds LIBPathOK(register __a0 char *str)
  1356. {
  1357.   BPTR FL;
  1358.  
  1359.   if (LIBAssignOK(str))
  1360.   {
  1361.     if (FL=Lock(str,ACCESS_READ))
  1362.     {
  1363.       UnLock(FL);
  1364.       return(TRUE);
  1365.     }
  1366.   }
  1367.   return(FALSE);
  1368. }
  1369.  
  1370. BOOL  __asm __saveds LIBHBBS_LoadUser(register __d0 V_BIGNUM ID,register __a0 char *handle,register __a1 char *realname,register __a2 struct UserData *user)
  1371. {
  1372.   // specify only one of ID,handle or realname
  1373.   // "user" should already be allocated..
  1374.  
  1375.   BPTR FH;
  1376.   BPTR FL;
  1377.   V_BOOL Found=FALSE;
  1378.  
  1379.   if(user)
  1380.   {
  1381.     if (ID>0)
  1382.     {
  1383.       // keep trying.. *C* add error checking here to check existance of the file!
  1384.       while (!(FL=Lock(BBSGlobal->UserDataFileName,ACCESS_READ)));
  1385.       if (FH=OpenFromLock(FL))
  1386.       {
  1387.         if (Seek(FH,(ID-1)*sizeof(struct UserData),OFFSET_BEGINNING)!=-1)
  1388.         {
  1389.           if (Read(FH,user,sizeof(struct UserData))==sizeof(struct UserData))
  1390.           {
  1391.             Found=TRUE;
  1392.           }
  1393.           // else puts("Short Read!");
  1394.         }
  1395.         Close(FH);
  1396.       }
  1397.       // else puts("Error Opening Userdata file");
  1398.       if (Found) return(TRUE);
  1399.     }
  1400.     else
  1401.     {
  1402.       if (handle!=NULL) // *C* Implement!
  1403.       {
  1404. //      printf("Searching for user with a handle of %s\n",handle);
  1405.       }
  1406.       else
  1407.       {
  1408.         if (realname!=NULL) // *C* Implement!
  1409.         {
  1410. //        printf("Searching for user with a realname of %s\n",realname);
  1411.         }
  1412.       }
  1413.     }
  1414.   }
  1415.   return(FALSE);
  1416. }
  1417.  
  1418. V_BOOL __asm __saveds LIBHBBS_ValidUserHandle(register __a0 char *userhandle, register __a1 struct UserData *FillUser)
  1419. {
  1420.  
  1421.   // Small routing to see if a user name does exist, if the user does
  1422.   // exist and FillUser points an allocated data structure the size of
  1423.   // sizeof(struct UserData) then the uses info that was found will be copied
  1424.   // to there.
  1425.  
  1426.   V_BIGNUM CurrentUserNum=0;
  1427.   V_BOOL Found=FALSE;
  1428.   struct UserData User;
  1429.  
  1430.   if (BBSGlobal->TotalUsers>=0) // spose we better check this :-)
  1431.   {
  1432.  
  1433.     // *C* change me, TotalUsers DOES NOT REFLECT amount of users in the userdata file
  1434.     // we just need a while loop that checks found and failure of HBBS_LoadUser
  1435.  
  1436.     while (!Found && CurrentUserNum<BBSGlobal->TotalUsers)
  1437.     {
  1438.       CurrentUserNum++;
  1439.       // printf("Searching %d For User \"%s\"\n",CurrentUserNum,userhandle);
  1440.       if (LIBHBBS_LoadUser(CurrentUserNum,NULL,NULL,&User))
  1441.       {
  1442.         // *C* insert pattern matching routine here..
  1443.         // or not ?  perhps add an "Interactive Y/N" parameter.
  1444.  
  1445.         if (stricmp(userhandle,User.Handle)==0)
  1446.         {
  1447.           Found=TRUE;
  1448.         }
  1449.       }
  1450.       // else puts("Failed To Load User");
  1451.     }
  1452.   }
  1453.   if (Found && FillUser)
  1454.   {
  1455.  
  1456.     CopyMem(&User,FillUser,sizeof (struct UserData));
  1457.   }
  1458.   return(Found);
  1459. }
  1460.  
  1461. V_BIGNUM __asm __saveds LIBHBBS_FindTotalUsers( void )
  1462. {
  1463.   BPTR FL;
  1464.   struct FileInfoBlock FB;
  1465.  
  1466.   BBSGlobal->TotalUsers=-1;
  1467.  
  1468.   // keep trying!
  1469.  
  1470.   while (!(FL=Lock(BBSGlobal->UserDataFileName,ACCESS_READ)));
  1471.   if (Examine(FL,&FB));
  1472.   {
  1473.     BBSGlobal->TotalUsers=(V_BIGNUM)(FB.fib_Size / sizeof(struct UserData));
  1474.   }
  1475.   UnLock(FL);
  1476.  
  1477.   return(BBSGlobal->TotalUsers);
  1478. }
  1479.  
  1480. BOOL __asm __saveds LIBLoadPrivateData( void )
  1481. {
  1482.   struct CfgFileData *PrivateCFG;
  1483.   BOOL retval=FALSE;
  1484.  
  1485.   if (PrivateCFG=LIBHBBS_LoadConfig(FILE_PRIVATEDATA,LCFG_NONE))
  1486.   {
  1487.     LIBHBBS_GetSetting(PrivateCFG,(void *)&BBSGlobal->CallsEver,VTYPE_BIGNUM,OPT_PRIV_CallsEver,OPT_SINGLE);
  1488.     if (LIBHBBS_GetSetting(PrivateCFG,(void *)&BBSGlobal->LastUserNum,VTYPE_BIGNUM,OPT_PRIV_LastUserNum,OPT_SINGLE))
  1489.     {
  1490.       retval=TRUE;
  1491.     }
  1492.     LIBHBBS_FlushConfig(PrivateCFG);
  1493.   }
  1494.  
  1495.   return(retval);
  1496. }
  1497.  
  1498. void __asm __saveds LIBUpdatePrivateData ( void )
  1499. {
  1500.   struct CfgFileData *PrivateCFG;
  1501.   char str[BIG_STR];
  1502.  
  1503.   if (PrivateCFG=LIBHBBS_CreateConfig(FILE_PRIVATEDATA))
  1504.   {
  1505.     sprintf(str,"%ld",BBSGlobal->CallsEver);
  1506.     LIBHBBS_AddCfgItemQuick(PrivateCFG,OPT_PRIV_CallsEver,str);
  1507.  
  1508.     sprintf(str,"%ld",BBSGlobal->LastUserNum);
  1509.     LIBHBBS_AddCfgItemQuick(PrivateCFG,OPT_PRIV_LastUserNum,str);
  1510.  
  1511.     LIBHBBS_SaveConfig(PrivateCFG);
  1512.     LIBHBBS_FlushConfig(PrivateCFG);
  1513.   }
  1514. }
  1515.  
  1516. BOOL __asm __saveds LIBHBBS_AddUser(register __a0 struct UserData *user)
  1517. {
  1518.   // *C* need to add some checking/locking of file for multinode operation..
  1519.  
  1520.   BPTR FH;
  1521.   BPTR FL;
  1522.  
  1523.   BOOL Saved=FALSE;
  1524.   char dirname[BIG_STR],filenote[80];
  1525.  
  1526.   // *C* need to check to see if file exists... (or get setup program to create..)
  1527.  
  1528.   // get exclusive access to userdata file when writing..
  1529.  
  1530.   while (!(FL=Lock(BBSGlobal->UserDataFileName,ACCESS_WRITE))); // keep trying..
  1531.  
  1532.   if (FH=OpenFromLock(FL)) //(BBSGlobal->UserDataFileName,MODE_OLDFILE))
  1533.   {
  1534.     if (Seek(FH,0,OFFSET_END)!=-1)
  1535.     {
  1536.       BBSGlobal->LastUserNum++;
  1537.       user->UserID=BBSGlobal->LastUserNum;
  1538.       if (Write(FH,user,sizeof(struct UserData))==sizeof(struct UserData))
  1539.       {
  1540.         LIBUpdatePrivateData();
  1541.  
  1542.  
  1543.         Saved=TRUE;
  1544.       }
  1545.       else
  1546.       {
  1547.         // puts("Error Adding Data To File, Truncating..");
  1548.         if (SetFileSize(FH,OFFSET_BEGINNING,BBSGlobal->TotalUsers * sizeof(struct UserData))==-1)
  1549.         {
  1550.           // puts("Cound Not Truncate File!");
  1551.         }
  1552.       }
  1553.     } // else puts("Seek() Failed!");
  1554.     Close(FH);
  1555.   }
  1556.   else UnLock(FL);
  1557.  
  1558.   if (Saved)
  1559.   {
  1560.     sprintf(filenote,"Handle: %s, Group: %s",user->Handle, user->Group);
  1561.  
  1562.     sprintf(dirname,"HBBS:System/Data/Users/%d",user->UserID);
  1563.     if (FL=CreateDir(dirname))
  1564.     {
  1565.       UnLock(FL);
  1566.       SetComment(dirname,filenote);
  1567.     }
  1568.  
  1569.     sprintf(dirname,"HBBS:Mail/Users/%d",user->UserID);
  1570.     if (FL=CreateDir(dirname))
  1571.     {
  1572.       UnLock(FL);
  1573.       SetComment(dirname,filenote);
  1574.     }
  1575.   }
  1576.  
  1577.   LIBHBBS_FindTotalUsers();
  1578.   return(Saved);
  1579. }
  1580.  
  1581. struct Node __asm __saveds *LIBHBBS_FindNode(register __a0 struct List *list,register __a1 char *str)
  1582. {
  1583.   struct Node *node,*retval=NULL;
  1584.   V_BOOL found=FALSE;
  1585.  
  1586.   if (list && str)
  1587.   {
  1588.     for (node=list->lh_Head;!found && node->ln_Succ;node=node->ln_Succ)
  1589.     {
  1590.       if (node->ln_Name)
  1591.       {
  1592.         if (stricmp(node->ln_Name,str)==0)
  1593.         {
  1594.           found=TRUE;
  1595.           retval=node;
  1596.         }
  1597.       }
  1598.     }
  1599.   }
  1600.   return(retval);
  1601. }
  1602.  
  1603. V_BIGNUM __asm __saveds LIBHBBS_FindNodeNum(register __a0 struct List *list, register __a1 char *str)
  1604. {
  1605.   struct Node *node;
  1606.   V_BIGNUM retval=-1;
  1607.   if (node=LIBHBBS_FindNode(list,str))
  1608.   {
  1609.     retval=LIBGetNodeNum(list,node);
  1610.   }
  1611.   return(retval);
  1612. }
  1613.  
  1614. void __asm __saveds LIBHBBS_InitUserData(register __a0 struct UserData *User,register __d0 V_BIGNUM AccessLevel,register __d1 V_BIGNUM ConfNum)
  1615. {
  1616.   struct Node *node;
  1617.   char tmpstr[BIG_STR];
  1618.   int num;
  1619.  
  1620.   User->Status=USER_NEW;
  1621.   User->Access=AccessLevel;
  1622.   User->Handle[0]=0;
  1623.   User->RealName[0]=0;
  1624.   User->Group[0]=0;
  1625.   User->GeoLocation[0]=0;
  1626.   User->Country[0]=0;
  1627.   User->PhoneNumber[0]=0;
  1628.   User->Password[0]=0;
  1629.   User->ComputerType[0]=0;
  1630.   User->SentBy[0]=0;
  1631.  
  1632.   User->ConfAcsDataFile[0]=0;
  1633.  
  1634.   sprintf(tmpstr,"%d",AccessLevel);
  1635.   if ((num=LIBHBBS_FindNodeNum(BBSGlobal->AcsLevelList,tmpstr))!=-1)
  1636.   {
  1637.     node=LIBGetNode(BBSGlobal->AcsLevelConfAcsDef,num);
  1638.     strcpy(User->ConfAcsDataFile,node->ln_Name);
  1639.   }
  1640.   User->LeechAccDataFile[0]=0;
  1641.   User->UploadBytes=0;
  1642.   User->UploadFiles=0;
  1643.   User->DownloadBytes=0;
  1644.   User->DownloadFiles=0;
  1645.   User->ActualUploadBytes=0;
  1646.   User->ActualUploadFiles=0;
  1647.   User->ActualDownloadBytes=0;
  1648.   User->ActualDownloadFiles=0;
  1649.   User->LastUploadDate=0; // *C* add HBBS_Todate() ?
  1650.   User->LastCalledDate=0;
  1651.   User->BestCPSUp=0;
  1652.   User->BestCPSDown=0;
  1653.   User->CallsMade=0;
  1654.   User->PagesMade=0;
  1655.   User->MessagesWritten=0;
  1656.   User->FilesRatio=3;
  1657.   User->BytesRatio=3;
  1658.   User->LastConf=ConfNum;
  1659.   User->PreferedConf=0;
  1660.   User->LinesPerScreen=24;
  1661.   User->Protocol=0; // ASK
  1662.   User->Editor=0; // ASK
  1663.   User->TimeAccessFile[0]=0;
  1664.   User->ExtraTimeLimit=0;
  1665.   User->ExtraBytesLimit=0;
  1666.   User->ExtraCallsLimit=0;
  1667.   User->ExtraChatLimit=0;
  1668.   User->TimeUsed=0;
  1669.   User->BytesUsed=0;
  1670.   User->CallsUsed=0;
  1671.   User->ChatUsed=0;
  1672.   User->BytesAllowed=0;
  1673.   User->TimeAllowed=0;
  1674.   User->CallsAllowed=0;
  1675.   User->ChatAllowed=0;
  1676.   User->UserType=USERTYPE_NORMAL;
  1677.   User->Language=0; // .TXT or the first one in the list..
  1678. }
  1679.  
  1680. void __asm __saveds LIBstrNcpy(register __a0 UBYTE *dest,register __a1 UBYTE *source,register __d0 int chars)
  1681. {
  1682.   int count=0;
  1683.  
  1684.   while ((dest[count]=source[count]) && count<chars-1) count++;
  1685.   dest[count+1]=0;
  1686. }
  1687.  
  1688. char __asm __saveds *LIBHBBS_ListName(register __a0 V_STRINGLIST ListName,register __d0 V_SMALLNUM ItemNum)
  1689. { //starts from offset 0, 0 being the first node in the list..
  1690.   struct Node *node;
  1691.  
  1692.   if(node=LIBGetNode(ListName,ItemNum))
  1693.   {
  1694.     return(node->ln_Name);
  1695.   }
  1696.   return(NULL);
  1697. }
  1698.  
  1699. void __asm __saveds LIBFreeFileTags( register __a0 struct NodeData *N_ND )
  1700. {
  1701.   struct TaggedFile *tfnode;
  1702.   while ((N_ND->TaggedFileList) && (N_ND->TaggedFileList->lh_Head->ln_Succ))
  1703.   {
  1704.     tfnode=(struct TaggedFile *)N_ND->TaggedFileList->lh_Head;
  1705.     LIBFreeStr(tfnode->node.ln_Name);
  1706.     Remove((struct Node*)tfnode);
  1707.     FreeVec(tfnode);
  1708.   }
  1709.   N_ND->TaggedFiles=0;
  1710. }
  1711.  
  1712. /*
  1713.  
  1714.  
  1715. struct List __asm __saveds *LIBHBBS_LoadFile(register __a0 char *filename)
  1716. {
  1717.   BPTR FL,FH;
  1718.   LONG bufferpos;
  1719.   BOOL done;
  1720.   struct FileInfoBlock FB;
  1721.   UBYTE *Data=NULL;
  1722.   LONG Length=0,filepos=0;
  1723.   UBYTE buffer[bufflen];
  1724.   struct List *FileList=NULL;
  1725.  
  1726.   if (FL=Lock(filename,ACCESS_READ))
  1727.   {
  1728.     if (Examine(FL,&FB))
  1729.     {
  1730.       if (FB.fib_Size)
  1731.       {
  1732.         if (Data=AllocVec(FB.fib_Size,MEMF_PUBLIC))
  1733.         {
  1734.           if (FH=OpenFromLock(FL))
  1735.           {
  1736.             Length=Read(FH,Data,FB.fib_Size);
  1737.             Close(FH);
  1738.           }
  1739.         }
  1740.       }
  1741.     }
  1742.     UnLock(FL);
  1743.  
  1744.     if ((Data) && (Length>0))
  1745.     {
  1746.       if (FileList=LIBHBBS_CreateList())
  1747.       {
  1748.  
  1749.         do
  1750.         {
  1751.           bufferpos=0;
  1752.           done=FALSE;
  1753.           do
  1754.           {
  1755.  
  1756.             if (Data[filepos]==13) //cr
  1757.             {
  1758.               if ((filepos+1<Length) && (Data[filepos+1]==10)) // cr followed by lf ?
  1759.               {
  1760.                 done=TRUE;
  1761.                 filepos++;//skip the lf too.
  1762.               }
  1763.               else
  1764.               {
  1765.                 done=TRUE;
  1766.               }
  1767.               filepos++; //skip the cr
  1768.             }
  1769.             else
  1770.             {
  1771.               if (Data[filepos]==10) //lf
  1772.               {
  1773.                 done=TRUE;
  1774.                 filepos++;
  1775.               }
  1776.               else
  1777.               {
  1778.                 buffer[bufferpos]=Data[filepos];
  1779.                 filepos++;
  1780.                 bufferpos++;
  1781.               }
  1782.             }
  1783.           } while (filepos<Length && !done && bufferpos<bufflen-2); // 1 for null and 1 more cos we still have to add the null
  1784.           buffer[bufferpos]=0;
  1785.  
  1786.           LIBNewStrNode(buffer,FileList);
  1787.  
  1788.         } while (filepos<Length);
  1789.       }
  1790.     }
  1791.     if (Data) FreeVec(Data);
  1792.   }
  1793.   return(FileList);
  1794. }
  1795. */
  1796.  
  1797.  
  1798. #define bufflen 1024
  1799.  
  1800. struct List __asm __saveds *LIBHBBS_LoadFile(register __a0 char *filename)
  1801. {
  1802.   /* New Optimized Version: 4-JAN-1996 */
  1803.  
  1804.   BPTR FH;
  1805.   UBYTE buffer[bufflen];
  1806.   struct List *FileList=NULL;
  1807.   BOOL error=FALSE;
  1808.  
  1809.   if (LIBPathOK(filename))
  1810.   {
  1811.     if (FH=Open(filename,MODE_OLDFILE))
  1812.     {
  1813.       if (FileList=LIBHBBS_CreateList())
  1814.       {
  1815.         while (FGets(FH,buffer,bufflen) && !error)
  1816.         {
  1817.           LIBstripcr(buffer);
  1818.           if (LIBNewStrNode(buffer,FileList))
  1819.           {
  1820.             error=TRUE;
  1821.           }
  1822.         }
  1823.       }
  1824.       Close(FH);
  1825.     }
  1826.   }
  1827.   if (error)
  1828.   {
  1829.     LIBFreeStrList(FileList);
  1830.     FileList=NULL;
  1831.   }
  1832.   return(FileList);
  1833. }
  1834.  
  1835.  
  1836. BOOL __asm __saveds LIBHBBS_SaveFile( register __a0 char *file_name, register __a1 struct List *list)
  1837. {
  1838.   BPTR FH;
  1839.   struct Node *node;
  1840.  
  1841.   if (FH=Open(file_name,MODE_NEWFILE))
  1842.   {
  1843.     for (node = list->lh_Head ; node->ln_Succ ; node =node->ln_Succ)
  1844.     {
  1845.       Write(FH,node->ln_Name,strlen(node->ln_Name));
  1846.       Write(FH,"\n",1); //add cr+lf
  1847.     }
  1848.     Close(FH);
  1849.   }
  1850.   return((BOOL)(FH ? TRUE : FALSE));
  1851. }
  1852.  
  1853. struct List __asm __saveds *LIBHBBS_CreateList( void )
  1854. {
  1855.   struct List *NList;
  1856.   if (NList=AllocVec(sizeof(struct List),MEMF_PUBLIC))
  1857.   {
  1858.     NewList(NList);
  1859.   }
  1860.   return(NList);
  1861. }
  1862.  
  1863. void __asm __saveds LIBstrftcpy(register __a0 char *dest,register __a1  char *source,register __d0 int from,register __d1 int topos)
  1864. {
  1865.   int loop=from,pos=0;
  1866.   if (from<=strlen(source)-1)
  1867.   {
  1868.     while (source[loop] && loop<=topos)
  1869.     {
  1870.       dest[pos]=source[loop];
  1871.       loop++;
  1872.       pos++;
  1873.     }
  1874.   }
  1875.   dest[pos]=0;
  1876. }
  1877.  
  1878. void __asm __saveds LIBRemoveSpaces(register __a0 char *string)
  1879. {
  1880.   // removes spaces from the start end end of strings
  1881.   ULONG start,end,len;
  1882.  
  1883.   if (string)
  1884.   {
  1885.     len=strlen(string);
  1886.     for (start=0;string[start]==' ';start++);
  1887.     for (end=len-1;string[end]==' ';end--);
  1888.     LIBstrftcpy(string,string,start,end);
  1889.   }
  1890. }
  1891.  
  1892.  
  1893. void __asm __saveds LIBHBBS_SaveUserData(register __a0 struct UserData *User)
  1894. {
  1895.   // *C* here we should save the data in N_ND->User.NormalData
  1896.   // back to the user file..
  1897.  
  1898.   BPTR FH,FL;
  1899.   BOOL Found,ReadError=FALSE;
  1900.   struct UserData OldUser;
  1901.  
  1902.   while (!(FL=Lock(BBSGlobal->UserDataFileName,ACCESS_WRITE)));
  1903.   if (FH=OpenFromLock(FL))
  1904.   {
  1905.     Found=FALSE;
  1906.     while (!Found && !ReadError)
  1907.     {
  1908.       // keep going until the end of the file or we get a read error..
  1909.       ReadError=((Read(FH,&OldUser,sizeof(struct UserData))==sizeof(struct UserData)) ? FALSE : TRUE );
  1910.  
  1911.       if (!ReadError)
  1912.       {
  1913.         if (OldUser.UserID==User->UserID)
  1914.         {
  1915.           Found=TRUE;
  1916.         }
  1917.       }
  1918.     }
  1919.     if (Found)
  1920.     {
  1921.       // *C* if error on next to commands then loop until it works ?
  1922.  
  1923.       // seek to start of record.
  1924.       Seek(FH,0-sizeof(struct UserData),OFFSET_CURRENT);
  1925.       Write(FH,User,sizeof(struct UserData));
  1926.     }
  1927.     Close(FH);
  1928.   }
  1929.   else UnLock(FL);
  1930. }
  1931.  
  1932. void __asm __saveds LIBHBBS_GetDate(register __a0 char *datestr)
  1933. {
  1934.   struct tm *timestruct;
  1935.   long t;
  1936.   if (datestr)
  1937.   {
  1938.     time(&t);
  1939.     timestruct=localtime(&t);
  1940.  
  1941.     LIBHBBS_DateStrFromTM(datestr,timestruct);
  1942.  
  1943. /*
  1944.     sprintf(datestr,"%s%d-%s-%-04d",(timestruct->tm_mday < 10) ? "0" : "",timestruct->tm_mday,monthstr[timestruct->tm_mon],timestruct->tm_year + 1900);
  1945. */
  1946.   }
  1947.   free(timestruct);
  1948. }
  1949.  
  1950. V_BOOL __asm __saveds LIBHBBS_AddCfgItemQuick(register __a0 struct CfgFileData *cfgfile,register __a1 char *ItemName, register __a2 char *Params)
  1951. {
  1952.   struct CfgItemData *node;
  1953.   V_BOOL retval=FALSE;
  1954.  
  1955.   if (cfgfile && ItemName && Params)
  1956.   {
  1957.     if (node=AllocVec(sizeof(struct CfgItemData),MEMF_PUBLIC))
  1958.     {
  1959.       node->node.ln_Name=LIBDupStr(ItemName);     // *C* error check me! (or not ?)
  1960.       node->Params=LIBDupStr(Params);
  1961.       AddTail(cfgfile->ItemsList,(struct Node*)node);
  1962.       retval=TRUE;
  1963.     }
  1964.   }
  1965.   return(retval);
  1966. }
  1967.  
  1968. void __asm __saveds LIBHBBS_SaveCallsData( void )
  1969. {
  1970.   struct CfgFileData *CfgFile;
  1971.   struct NodeData *nd;
  1972.   UBYTE tmpstr[200],optionstr[200];
  1973.  
  1974.  
  1975.   if (CfgFile=LIBHBBS_CreateConfig("HBBS:System/Data/Calls.CFG"))
  1976.   {
  1977.     LIBHBBS_GetDate(tmpstr);
  1978.     LIBHBBS_AddCfgItemQuick(CfgFile,"Today",tmpstr);
  1979.  
  1980.     sprintf(tmpstr,"%d",BBSGlobal->CallsToday);
  1981.     LIBHBBS_AddCfgItemQuick(CfgFile,"TotalCalls",tmpstr);
  1982.  
  1983.     for (nd=(struct NodeData *)BBSGlobal->NodeList->lh_Head;nd->node.ln_Succ;nd=(struct NodeData *)nd->node.ln_Succ)
  1984.     {
  1985.       sprintf(optionstr,"Node_%d_Calls",nd->NodeNum);
  1986.       sprintf(tmpstr,"%d",nd->CallsToday);
  1987.       LIBHBBS_AddCfgItemQuick(CfgFile,optionstr,tmpstr);
  1988.     }
  1989.     LIBHBBS_SaveConfig(CfgFile);
  1990.     LIBHBBS_FlushConfig(CfgFile);
  1991.   }
  1992.  
  1993. }
  1994.  
  1995. void __asm __saveds LIBHBBS_LoadCallsData( void )
  1996. {
  1997.   struct CfgFileData *CfgFile;
  1998.   BOOL Loaded=FALSE;
  1999.   V_STRING TodayStr=NULL;
  2000.   UBYTE tmpstr[200];
  2001.   struct NodeData *nd;
  2002.  
  2003.   LIBHBBS_GetDate(tmpstr);
  2004.  
  2005.   if (CfgFile=LIBHBBS_LoadConfig("HBBS:System/Data/Calls.CFG",LCFG_NONE))
  2006.   {
  2007.     if (LIBHBBS_GetSetting(CfgFile,(void *)&TodayStr,VTYPE_STRING,"Today",OPT_SINGLE))
  2008.     {
  2009.       if (stricmp(TodayStr,tmpstr)==0) // same day ???
  2010.       {
  2011.         if (LIBHBBS_GetSetting(CfgFile,(void *)&BBSGlobal->CallsToday,VTYPE_BIGNUM,"TotalCalls",OPT_SINGLE))
  2012.         {
  2013.           for (nd=(struct NodeData *)BBSGlobal->NodeList->lh_Head;nd->node.ln_Succ;nd=(struct NodeData *)nd->node.ln_Succ)
  2014.           {
  2015.             sprintf(tmpstr,"Node_%d_Calls",nd->NodeNum);
  2016.             if (!LIBHBBS_GetSetting(CfgFile,(void *)&nd->CallsToday,VTYPE_BIGNUM,tmpstr,OPT_SINGLE))
  2017.             {
  2018.               nd->CallsToday=0;
  2019.             }
  2020.           }
  2021.           Loaded=TRUE;
  2022.         }
  2023.       }
  2024.     }
  2025.   }
  2026.   if (!Loaded)
  2027.   {
  2028.     BBSGlobal->CallsToday=0;
  2029.  
  2030.     for (nd=(struct NodeData *)BBSGlobal->NodeList->lh_Head;nd->node.ln_Succ;nd=(struct NodeData *)nd->node.ln_Succ)
  2031.     {
  2032.       nd->CallsToday=0;
  2033.     }
  2034.     LIBHBBS_SaveCallsData();
  2035.   }
  2036.   if (TodayStr) LIBFreeStr(TodayStr);
  2037. }
  2038.  
  2039. void __asm __saveds LIBHBBS_GetTime(register __a0 char *timestr)
  2040. {
  2041.   struct tm *timestruct;
  2042.   long t;
  2043.  
  2044.   if (timestr)
  2045.   {
  2046.     time(&t);
  2047.     timestruct=localtime(&t);
  2048.  
  2049.     sprintf(timestr,"%s%d:%s%d:%s%d",(timestruct->tm_hour < 10) ? "0" : "",timestruct->tm_hour,
  2050.                                      (timestruct->tm_min < 10) ? "0" : "",timestruct->tm_min,
  2051.                                      (timestruct->tm_sec < 10) ? "0" : "",timestruct->tm_sec);
  2052.   }
  2053.   free(timestruct);
  2054. }
  2055.  
  2056. void __asm __saveds LIBHBBS_GetDateStr(register __a0 char *datestr,register __d0 long t)
  2057. {
  2058.   long tt=t;
  2059.   struct tm *timestruct;
  2060.   if (datestr)
  2061.   {
  2062.     timestruct=localtime(&tt);
  2063.  
  2064. /*
  2065.     if (timestruct->tm_mday<0)
  2066.     {
  2067.       strcpy(datestr,"01-JAN-1970"); // date limit!
  2068.     }
  2069.     else
  2070.     {
  2071.       sprintf(datestr,"%s%d-%s-%-04d",(timestruct->tm_mday < 10) ? "0" : "",timestruct->tm_mday,monthstr[timestruct->tm_mon],timestruct->tm_year+1900);
  2072.     }
  2073. */
  2074.     LIBHBBS_DateStrFromTM(datestr,timestruct);
  2075.     free(timestruct);
  2076.   }
  2077. }
  2078.  
  2079. void __asm __saveds LIBHBBS_DateStrFromTM(register __a0 UBYTE *datestr, register __a1 struct tm *timestruct)
  2080. {
  2081.   if (datestr && timestruct)
  2082.   {
  2083.     if (timestruct->tm_mday<0)
  2084.     {
  2085.       strcpy(datestr,"01-JAN-1970"); // date limit!
  2086.     }
  2087.     else
  2088.     {
  2089.       sprintf(datestr,"%s%d-%s-%-04d",(timestruct->tm_mday < 10) ? "0" : "",timestruct->tm_mday,monthstr[timestruct->tm_mon],timestruct->tm_year+1900);
  2090.     }
  2091.   }
  2092.  
  2093. }
  2094.  
  2095. V_BOOL __asm __saveds LIBHBBS_DateStrToTM(register __a0 UBYTE *datestr, register __a1 struct tm *timestruct)
  2096. {
  2097.   UBYTE tmpstr[5];
  2098.   LONG tday,tmon=-1,tyear,loop;
  2099.  
  2100.   LIBstrNcpy(tmpstr,datestr,2);
  2101.   if (sscanf(tmpstr,"%ld",&tday))
  2102.   {
  2103.     LIBstrftcpy(tmpstr,datestr,3,5);
  2104.     for (loop=0;loop<=12 && tmon==-1;loop++)
  2105.     {
  2106.       if (stricmp(tmpstr,monthstr[loop])==0)
  2107.       {
  2108.         tmon=loop;
  2109.       }
  2110.     }
  2111.     if (tmon>=0)
  2112.     {
  2113.       LIBstrftcpy(tmpstr,datestr,7,10);
  2114.       if (sscanf(tmpstr,"%ld",&
  2115.       tyear))
  2116.       {
  2117.         tyear-=1900;
  2118.         if ((tyear>=70) && (tmon>=0) && (tmon<12) && (tday>=1) && (tday<=31))
  2119.         {
  2120.           // all data is ok, so opy it to the timestruct!
  2121.           timestruct->tm_mday=tday;
  2122.           timestruct->tm_year=tyear;
  2123.           timestruct->tm_mon=tmon;
  2124.           return(TRUE);
  2125.         }
  2126.       }
  2127.     }
  2128.   }
  2129.   return(FALSE);
  2130. }
  2131.  
  2132. void *AllocBuffer(ULONG *BufferSize,ULONG Flags) // min 10 bytes!
  2133. {
  2134.   void *retval=NULL;
  2135.  
  2136.   if (*BufferSize)
  2137.   {
  2138.     if (*BufferSize<10) *BufferSize=10;
  2139.     while ((*BufferSize>10) && ((retval=AllocVec(*BufferSize,Flags))==NULL))
  2140.     {
  2141.       *BufferSize/=2; // divide buffersize by 2!
  2142.     }
  2143.  
  2144.   }
  2145.   return(retval);
  2146. }
  2147.  
  2148. V_BOOL __asm __saveds LIBHBBS_CopyFile(register __a0 char *fromfile, register __a1 char *tofile,register __d0 ULONG BufSize)
  2149. {
  2150.   BOOL retval=FALSE;
  2151.   BPTR FL,FromFH,ToFH;
  2152.   struct FileInfoBlock FB;
  2153.   BOOL error=TRUE;
  2154.   ULONG nr,nw,total=0;
  2155.   UBYTE *Buffer;
  2156.   ULONG MyBufSize=BufSize;
  2157.  
  2158.   if (MyBufSize==0) MyBufSize=BBSGlobal->CopyBufferSize; // *C* user selectable!
  2159.  
  2160.   if (FL=Lock(fromfile,ACCESS_READ))
  2161.   {
  2162.     if (Examine(FL,&FB))
  2163.     {
  2164.       if (FromFH=OpenFromLock(FL))
  2165.       {
  2166.         if (ToFH=Open(tofile,MODE_NEWFILE))
  2167.         {
  2168.           if (FB.fib_Size>0)
  2169.           {
  2170.             if (MyBufSize>FB.fib_Size) MyBufSize=FB.fib_Size; // no sense allocating to much mem
  2171.             if (Buffer=AllocBuffer(&MyBufSize,MEMF_PUBLIC))
  2172.             {
  2173.               do
  2174.               {
  2175.                 error=FALSE;
  2176.                 if (nr=Read(FromFH,Buffer,MyBufSize-1))
  2177.                 {
  2178.                   if (nr==(nw=Write(ToFH,Buffer,nr)))
  2179.                   {
  2180.                     total+=nw;
  2181.                   } else error=TRUE;
  2182.                 } else error=TRUE;
  2183.               } while (!error);
  2184.               if (error && total>=FB.fib_Size) error=FALSE; //end of file rather than error...
  2185.  
  2186.               FreeVec(Buffer);
  2187.             }
  2188.           }
  2189.           else
  2190.           {
  2191.             error=FALSE;
  2192.           }
  2193.           Close(ToFH);
  2194.           SetComment(tofile,FB.fib_Comment);
  2195.           SetProtection(tofile,FB.fib_Protection);
  2196.         }
  2197.         Close(FromFH);
  2198.         FL=NULL;
  2199.       }
  2200.     }
  2201.     if (FL) UnLock(FL);
  2202.   }
  2203.   if (!error)
  2204.   {
  2205.     retval=TRUE;
  2206. //    if (FL=Lock(tofile,ACCESS_READ)) // is the new file the same as the old one ?
  2207. //    {
  2208. //      total=FB.fib_Size;
  2209. //      if (Examine(FL,&FB) && total==FB.fib_Size) retval=TRUE;
  2210. //      UnLock(FL);
  2211. //    }
  2212.   }
  2213.  
  2214.   if (!retval) // if the old file is different then delete it..
  2215.   {
  2216.     DeleteFile(tofile);
  2217.   }
  2218.   return(retval);
  2219. }
  2220.  
  2221. ULONG __asm __saveds LIBHBBS_NodesInList(register __a0 struct List *list)
  2222. {
  2223.   struct Node *node;
  2224.   ULONG Nodes=0;
  2225.   if (list)
  2226.   {
  2227.     for (node=list->lh_Head;node->ln_Succ;node=node->ln_Succ)
  2228.     {
  2229.       Nodes++;
  2230.     }
  2231.     return(Nodes);
  2232.   }
  2233.   return(0);
  2234. }
  2235.  
  2236. V_BOOL __asm __saveds LIBHBBS_AppendStrToFile(register __a0 UBYTE *FileName, register __a1 UBYTE *String)
  2237. {
  2238.   BPTR FH;
  2239.   V_BOOL retval=FALSE;
  2240.  
  2241.   if (LIBAssignOK(FileName))
  2242.   {
  2243.     if (FH=Open(FileName,MODE_READWRITE))
  2244.     {
  2245.       Seek(FH,0,OFFSET_END);
  2246.       if (Write(FH,String,strlen(String))==strlen(String)) retval=TRUE;
  2247.  
  2248.       Close(FH);
  2249.     }
  2250.   }
  2251.   return(retval);
  2252. }
  2253.  
  2254.  
  2255. /*
  2256.    HBBS_CreateNode() creates a node and returns a pointer to it.
  2257.  
  2258.    if namestr is not NULL then the a new string will be allocated and
  2259.    placed the ln_Name field.
  2260.  
  2261.    if you specify 0 for the nodesize, then the size of the node allocated
  2262.    will be the sizeof(struct Node), otherwise it'll allocate however many bytes
  2263.    you specify.
  2264.  
  2265.    All the data will be zero'd, so all your other fields will be intialized to NULL
  2266.    or 0!
  2267.  
  2268. */
  2269.  
  2270. struct Node __asm __saveds *LIBHBBS_CreateNode(register __a0 char *namestr,register __d0 ULONG nodesize)
  2271. {
  2272.   struct Node *newnode;
  2273.  
  2274.   if (nodesize==0) nodesize=sizeof(struct Node);
  2275.  
  2276.   if (newnode=AllocVec(nodesize,MEMF_CLEAR|MEMF_PUBLIC))
  2277.   {
  2278.     if (namestr)
  2279.     {
  2280.       if (!(newnode->ln_Name=LIBDupStr(namestr)))
  2281.       {
  2282.         FreeVec(newnode);
  2283.         newnode=NULL; // failed!
  2284.       }
  2285.     }
  2286.   }
  2287.   return(newnode);  // NULL if not enough mem, or pointer to node otherwise..
  2288. }
  2289.  
  2290. void __asm __saveds LIBHBBS_FreeNode(register __a0 struct Node *node,register __d0 V_BOOL RemoveIt)
  2291. {
  2292.   if (node)
  2293.   {
  2294.     if (RemoveIt) Remove(node);
  2295.     if (node->ln_Name) LIBFreeStr(node->ln_Name);
  2296.     FreeVec(node);
  2297.   }
  2298. }
  2299.  
  2300. void __asm __saveds LIBHBBS_FreeListNodes(register __a0 struct List *list)
  2301. {
  2302.   // free all ln_Names of each node in a list and remove all nodes from the list!
  2303.   // but we DON't free the list itself, we just leave it empty
  2304.  
  2305.   struct Node *node;
  2306.   if (list)
  2307.   {
  2308.     while (list->lh_Head->ln_Succ)
  2309.     {
  2310.       node=list->lh_Head;
  2311.       LIBFreeStr(node->ln_Name);
  2312.       Remove(node);
  2313.       FreeVec(node);
  2314.     }
  2315.   }
  2316. }
  2317.  
  2318. V_BOOL __asm __saveds LIBHBBS_SendOLM(register __d0 V_SMALLNUM FromNode,register __a0 UBYTE *FromPRG,register __d1 V_SMALLNUM ToNode,register __a1 UBYTE *Message,register __d2 BYTE Pri)
  2319. {
  2320.   // frommnode should be 0 if something other than a door is sending the OLM
  2321.   // otheriwse fromnode should be set to your node number plus 1
  2322.   // e.g. N_ND->NodeNum+1, if fromnode
  2323.  
  2324.  
  2325.   V_BOOL retval=FALSE;
  2326.   struct OLMNode *NewOLM;
  2327.   struct NodeData *nd;
  2328.   struct NodeData *fnd;
  2329.   struct Message *NewMsg;
  2330.  
  2331.   // lets see if we can send an eall, node must be open and initalised with
  2332.   // a user loggined in and the status must be online
  2333.   if ((Message) &&
  2334.       (FromNode>=0 ) && (FromNode<=BBSGlobal->BBSNodes) &&
  2335.       (nd=LIBHBBS_NodeDataPtr(ToNode)) &&
  2336.       (nd->Status==STAT_ONLINE) &&
  2337.       (nd->OLMList) &&
  2338.       (nd->LoginType!=LOGIN_NONE) &&
  2339.       (nd->OnlineStatus==OS_ONLINE))
  2340.   {
  2341.     if (NewOLM=(struct OLMNode *)LIBHBBS_CreateNode(Message,sizeof(struct OLMNode)))
  2342.     {
  2343.       if (NewOLM->node.ln_Name=LIBDupStr(Message))
  2344.       {
  2345.         NewOLM->node.ln_Pri=Pri;
  2346.         LIBHBBS_GetTime(NewOLM->Time);
  2347.         LIBHBBS_GetDate(NewOLM->Date);
  2348.         NewOLM->FromNode=FromNode;
  2349.         if ((FromNode) && (fnd=LIBHBBS_NodeDataPtr(FromNode-1)))
  2350.         {
  2351.           if (fnd->User.Valid) // NewOLD has already been blanked by CreateNode() so the string is already null terminated..
  2352.           {
  2353.             LIBstrNcpy(NewOLM->Handle,fnd->User.CallData.Handle,LEN_HANDLE);
  2354.           }
  2355.         }
  2356.         if (FromPRG)
  2357.         {
  2358.           LIBstrNcpy(NewOLM->FromPRG,FromPRG,LEN_HANDLE);
  2359.         }
  2360.  
  2361.         // *C* add semaphore checking!
  2362.         Enqueue(nd->OLMList,(struct Node*)NewOLM);
  2363.         nd->OLMCount++;
  2364.         if (!(nd->NodeFlags & NFLG_OLMSWAITING)) nd->NodeFlags+=NFLG_OLMSWAITING;
  2365.  
  2366.         if (nd->OLMPort)
  2367.         {
  2368.           if (NewMsg=AllocVec(sizeof (struct Message),MEMF_PUBLIC|MEMF_CLEAR))
  2369.           {
  2370.             NewMsg->mn_Node.ln_Type = NT_MESSAGE;
  2371.             NewMsg->mn_ReplyPort=NULL;
  2372.             NewMsg->mn_Length=sizeof(struct Message);
  2373.  
  2374.             PutMsg(nd->OLMPort,NewMsg);
  2375.           }
  2376.         }
  2377.         retval=TRUE;
  2378.       }
  2379.     }
  2380.   }
  2381.   return(retval);
  2382. }
  2383.  
  2384. BOOL __asm __saveds LIBFGetsR(register __a0 BPTR FH,register __a1 UBYTE *Buffer,register __d0 LONG BufferLen)
  2385. {
  2386.  
  2387.   // fucking amazing routine to read a file line by line but BACKWARDS from the current
  2388.   // position!! Whay!!
  2389.  
  2390.   LONG nr,where,back,foundpos=0;
  2391.   BOOL retval=TRUE,sof=FALSE,error=FALSE;
  2392.  
  2393.   UBYTE *strptr=NULL;
  2394.  
  2395.  
  2396.   Buffer[0]=0;
  2397.   BufferLen--;
  2398.  
  2399.   where=Seek(FH,0,OFFSET_CURRENT);  // start of file already ?
  2400.   if (where<=0) //start of file or error
  2401.   {
  2402.     retval=FALSE;
  2403.   }
  2404.   else
  2405.   {
  2406.     do
  2407.     {
  2408.       back=255;
  2409.       if (where<255) back=where;
  2410.  
  2411.       if (back>BufferLen) back=BufferLen;
  2412.  
  2413.       if ((where=Seek(FH,0-back,OFFSET_CURRENT))!=-1)
  2414.       {
  2415.         where-=back;
  2416.  
  2417.         if (nr=Read(FH,Buffer,back))
  2418.         {
  2419.           Buffer[nr]=0;
  2420.           if (strptr=strrchr(Buffer,'\n'))
  2421.           {
  2422.             foundpos=where+(strptr-Buffer);
  2423.             if (Seek(FH,foundpos+1,OFFSET_BEGINNING)==-1)
  2424.             {
  2425.               error=TRUE;
  2426.             }
  2427.           }
  2428.           else
  2429.           {
  2430.             if (where==0)
  2431.             {
  2432.               if (Seek(FH,0,OFFSET_BEGINNING)==-1)
  2433.               {
  2434.                 error=TRUE;
  2435.               }
  2436.               else
  2437.               {
  2438.                 sof=TRUE;
  2439.                 foundpos=1;
  2440.               }
  2441.             }
  2442.             else
  2443.             {
  2444.  
  2445.               if (Seek(FH,0-nr,OFFSET_CURRENT)!=-1)
  2446.               {
  2447.                 where-=nr;
  2448.               }
  2449.               else
  2450.               {
  2451.                 error=TRUE;
  2452.               }
  2453.             }
  2454.  
  2455.           }
  2456.         }
  2457.         else
  2458.         {
  2459.           error=TRUE;
  2460.         }
  2461.  
  2462.       }
  2463.     } while (strptr==NULL && !error && !sof);
  2464.  
  2465.     Buffer[0]=0;
  2466.     if (strptr || sof )
  2467.     {
  2468.       FGets(FH,Buffer,BufferLen);
  2469.       Seek(FH,foundpos ? foundpos-1 : 0,OFFSET_BEGINNING);
  2470.     }
  2471.   }
  2472.  
  2473.   return(retval);
  2474.  
  2475. }
  2476.  
  2477. V_BOOL __asm __saveds LIBHBBS_HandleNameOK(register __a0 char *checkstr)
  2478. {
  2479.   if (strchr(checkstr,',')) return(FALSE);
  2480.   if (strchr(checkstr,';')) return(FALSE);
  2481.   if (strchr(checkstr,'?')) return(FALSE);
  2482.   if (strchr(checkstr,'*')) return(FALSE);
  2483.   if (strchr(checkstr,'#')) return(FALSE);       // *C* optimze me..
  2484.   if (strchr(checkstr,'(')) return(FALSE);
  2485.   if (strchr(checkstr,')')) return(FALSE);
  2486.   return(TRUE);
  2487. }
  2488.  
  2489.